package com.wstuo.common.jbpm.action;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.jbpm.api.ProcessDefinition;
import org.jbpm.api.ProcessInstance;
import org.jbpm.api.history.HistoryProcessInstance;
import org.jbpm.api.identity.User;
import org.springframework.beans.factory.annotation.Autowired;

import com.opensymphony.xwork2.ActionSupport;
import com.wstuo.common.bpm.api.IBPD;
import com.wstuo.common.bpm.api.IBPI;
import com.wstuo.common.bpm.dto.ActivityCoordinatesDTO;
import com.wstuo.common.bpm.dto.FlowActivityDTO;
import com.wstuo.common.bpm.dto.FlowPropertyDTO;
import com.wstuo.common.bpm.dto.HistoryTaskDTO;
import com.wstuo.common.bpm.dto.ProcessDefinitionDTO;
import com.wstuo.common.bpm.dto.ProcessDetailDTO;
import com.wstuo.common.bpm.dto.ProcessHistoriesQueryDTO;
import com.wstuo.common.bpm.dto.ProcessUseDTO;
import com.wstuo.common.bpm.dto.TaskDTO;
import com.wstuo.common.bpm.dto.TaskQueryDTO;
import com.wstuo.common.bpm.service.IFlowPropertyService;
import com.wstuo.common.dto.PageDTO;
import com.wstuo.common.exception.ApplicationException;
import com.wstuo.common.jbpm.FlowDesigner;
import com.wstuo.common.jbpm.IJbpmFacade;
import com.wstuo.common.jbpm.dto.NodeDTO;
import com.wstuo.common.security.utils.AppConfigUtils;
import com.wstuo.common.security.utils.FileEncodeUtils;

/**
 * JBPM action class
 * @author wstuo
 */
@SuppressWarnings("serial")
public class JbpmAction extends ActionSupport {
    @Autowired
    protected IJbpmFacade jbpmFacade;
    @Autowired
    private IBPD bpd;
    @Autowired
    private IBPI bpi;
    @Autowired
    private IFlowPropertyService flowPropertyService;
    private File processFile;
    private String jpdlFileFileName;
    private String jpdlFileContentType;
    private String deploymentId;
    private String processDefinitionId;
    private String pid;
    private String processId;
    private String instanceId;
    private String taskId;
    private String assignee;
    private List<ProcessDefinition> process;
    private List<ProcessInstance> processInstances;
    private List<HistoryProcessInstance> histories;
    private InputStream imageInputStream;
    private List<TaskDTO> tasks;
    private List<User> users;
    private String groupId;
    private String[] userIds;
    private String toTaskName;
    private PageDTO pageDTO = new PageDTO();
    private int page = 1;
    private int rows = 10;
    private String sidx;
    private String sord;
    private ProcessUseDTO processUseDTO;
    private ProcessHistoriesQueryDTO processHistoriesQueryDTO;
    private String rawXml;
    private NodeDTO nodeDTO;
    private List<NodeDTO> nodeDTOList = new ArrayList<NodeDTO>();
    private InputStream exportStream;//输出流
    private Set<String> strSet;//字符串集
    private String activityName;//活动名
    private String loginName;//登录名
    private String outcome;
    private ProcessDefinitionDTO processDefinitionDTO;
    private ActivityCoordinatesDTO activityCoordinatesDTO;
    private List<ActivityCoordinatesDTO> activityHistoryCoordinatesDTO;
    private List<HistoryTaskDTO> htsDTO = new ArrayList<HistoryTaskDTO>();
    private String strResult;
    private FlowActivityDTO flowActivityDTO;
    private TaskQueryDTO queryDTO=new TaskQueryDTO();
    private List<ProcessDetailDTO> processDetailDTO;
    private Boolean result;
    private static final Logger LOGGER = Logger.getLogger(JbpmAction.class );
    
    public List<ActivityCoordinatesDTO> getActivityHistoryCoordinatesDTO() {
		return activityHistoryCoordinatesDTO;
	}
	public void setActivityHistoryCoordinatesDTO(
			List<ActivityCoordinatesDTO> activityHistoryCoordinatesDTO) {
		this.activityHistoryCoordinatesDTO = activityHistoryCoordinatesDTO;
	}
	public Boolean getResult() {
		return result;
	}
	public void setResult(Boolean result) {
		this.result = result;
	}
	public List<ProcessDetailDTO> getProcessDetailDTO() {
		return processDetailDTO;
	}
	public void setProcessDetailDTO(List<ProcessDetailDTO> processDetailDTO) {
		this.processDetailDTO = processDetailDTO;
	}
	public TaskQueryDTO getQueryDTO() {
		return queryDTO;
	}
	public void setQueryDTO(TaskQueryDTO queryDTO) {
		this.queryDTO = queryDTO;
	}
	public FlowActivityDTO getFlowActivityDTO() {
		return flowActivityDTO;
	}
	public void setFlowActivityDTO(FlowActivityDTO flowActivityDTO) {
		this.flowActivityDTO = flowActivityDTO;
	}
	public String getProcessDefinitionId() {
		return processDefinitionId;
	}
	public void setProcessDefinitionId(String processDefinitionId) {
		this.processDefinitionId = processDefinitionId;
	}
	public String getOutcome() {
		return outcome;
	}
	public void setOutcome(String outcome) {
		this.outcome = outcome;
	}
	public PageDTO getPageDTO() {
		return pageDTO;
	}
	public void setPageDTO(PageDTO pageDTO) {
		this.pageDTO = pageDTO;
	}

	public String getInstanceId() {

        return instanceId;
    }

    public void setInstanceId(String instanceId) {

        this.instanceId = instanceId;
    }

    public String getTaskId() {

        return taskId;
    }

    public void setTaskId(String taskId) {

        this.taskId = taskId;
    }

    public ActivityCoordinatesDTO getActivityCoordinatesDTO() {
		return activityCoordinatesDTO;
	}
	public void setActivityCoordinatesDTO(
			ActivityCoordinatesDTO activityCoordinatesDTO) {
		this.activityCoordinatesDTO = activityCoordinatesDTO;
	}
	public List<TaskDTO> getTasks() {

        return tasks;
    }

    public void setTasks(List<TaskDTO> tasks) {

        this.tasks = tasks;
    }

    public List<User> getUsers() {

        return users;
    }

    public void setUsers(List<User> users) {

        this.users = users;
    }


    public String getGroupId() {

        return groupId;
    }

    public void setGroupId(String groupId) {

        this.groupId = groupId;
    }

    public String[] getUserIds() {

        return userIds;
    }

    public void setUserIds(String[] userIds) {

        this.userIds = userIds;
    }

    public String getToTaskName() {

        return toTaskName;
    }

    public void setToTaskName(String toTaskName) {

        this.toTaskName = toTaskName;
    }

	public int getPage() {

        return page;
    }

    public void setPage(int page) {

        this.page = page;
    }

    public int getRows() {

        return rows;
    }

    public void setRows(int rows) {

        this.rows = rows;
    }
    public File getProcessFile() {
		return processFile;
	}
	public void setProcessFile(File processFile) {
		this.processFile = processFile;
	}
	public String getJpdlFileFileName() {

        return jpdlFileFileName;
    }

    public void setJpdlFileFileName(String jpdlFileFileName) {

        this.jpdlFileFileName = jpdlFileFileName;
    }

    public String getJpdlFileContentType() {

        return jpdlFileContentType;
    }

    public void setJpdlFileContentType(String jpdlFileContentType) {

        this.jpdlFileContentType = jpdlFileContentType;
    }

    public String getDeploymentId() {

        return deploymentId;
    }

    public void setDeploymentId(String deploymentId) {

        this.deploymentId = deploymentId;
    }

    public String getProcessId() {

        return processId;
    }

    public void setProcessId(String processId) {

        this.processId = processId;
    }

    public List<ProcessDefinition> getProcess() {

        return process;
    }

    public void setProcess(List<ProcessDefinition> process) {

        this.process = process;
    }

    public List<ProcessInstance> getProcessInstances() {

        return processInstances;
    }

    public void setProcessInstances(List<ProcessInstance> processInstances) {

        this.processInstances = processInstances;
    }

    public List<HistoryProcessInstance> getHistories() {

        return histories;
    }

    public void setHistories(List<HistoryProcessInstance> histories) {

        this.histories = histories;
    }
	public InputStream getImageInputStream() {
		return imageInputStream;
	}
	public void setImageInputStream(InputStream imageInputStream) {
		this.imageInputStream = imageInputStream;
	}
	public ProcessUseDTO getProcessUseDTO() {
		return processUseDTO;
	}

	public void setProcessUseDTO(ProcessUseDTO processUseDTO) {
		this.processUseDTO = processUseDTO;
	}
	public ProcessHistoriesQueryDTO getProcessHistoriesQueryDTO() {
		return processHistoriesQueryDTO;
	}
	public void setProcessHistoriesQueryDTO(
			ProcessHistoriesQueryDTO processHistoriesQueryDTO) {
		this.processHistoriesQueryDTO = processHistoriesQueryDTO;
	}
	public String getSidx() {
		return sidx;
	}

	public void setSidx(String sidx) {
		this.sidx = sidx;
	}

	public String getSord() {
		return sord;
	}

	public void setSord(String sord) {
		this.sord = sord;
	}
	
	public String getRawXml() {
		return rawXml;
	}

	public void setRawXml(String rawXml) {
		this.rawXml = rawXml;
	}

	public List<NodeDTO> getNodeDTOList() {
		return nodeDTOList;
	}

	public void setNodeDTOList(List<NodeDTO> nodeDTOList) {
		this.nodeDTOList = nodeDTOList;
	}

	public NodeDTO getNodeDTO() {
		return nodeDTO;
	}

	public void setNodeDTO(NodeDTO nodeDTO) {
		this.nodeDTO = nodeDTO;
	}

	public InputStream getExportStream() {
		return exportStream;
	}

	public void setExportStream(InputStream exportStream) {
		this.exportStream = exportStream;
	}

	public Set<String> getStrSet() {
		return strSet;
	}

	public void setStrSet(Set<String> strSet) {
		this.strSet = strSet;
	}
	
	public String getActivityName() {
		return activityName;
	}

	public void setActivityName(String activityName) {
		this.activityName = activityName;
	}
	public String getPid() {
		return pid;
	}
	public void setPid(String pid) {
		this.pid = pid;
	}
	public String getLoginName() {
		return loginName;
	}

	public void setLoginName(String loginName) {
		this.loginName = loginName;
	}

	
	public ProcessDefinitionDTO getProcessDefinitionDTO() {
		return processDefinitionDTO;
	}

	public void setProcessDefinitionDTO(ProcessDefinitionDTO processDefinitionDTO) {
		this.processDefinitionDTO = processDefinitionDTO;
	}

	public IBPD getBpd() {
		return bpd;
	}

	public void setBpd(IBPD bpd) {
		this.bpd = bpd;
	}

	public IBPI getBpi() {
		return bpi;
	}

	public void setBpi(IBPI bpi) {
		this.bpi = bpi;
	}

	public List<HistoryTaskDTO> getHtsDTO() {
		return htsDTO;
	}
	public void setHtsDTO(List<HistoryTaskDTO> htsDTO) {
		this.htsDTO = htsDTO;
	}

	public String getAssignee() {
		return assignee;
	}
	public void setAssignee(String assignee) {
		this.assignee = assignee;
	}
	
	public String getStrResult() {
		return strResult;
	}
	public void setStrResult(String strResult) {
		this.strResult = strResult;
	}
	
	/**
	 * 分页查询流程定义
	 * @return String
	 */
	public String findPageProcessDefinitions(){
		int start = (page - 1) * rows;
		pageDTO = bpd.findPageProcessDefinitions(processDefinitionDTO, start, rows, sord, sidx);
		pageDTO.setPage(page);
		pageDTO.setRows(rows);
		return SUCCESS;
	}
	
	/**
	 * 布署流程ZIP
	 * @return String
	 */
	public String deployProcessDefinitionFile(){
		strResult = bpd.deployProcessDefinitionFile(processFile);
		return "strResult";
	}
	
	/**
	 * 布署流程ZIP
	 * @return String
	 */
	public String deployProcessDefinitionXmlFile(){
		strResult = bpd.deployProcessDefinitionXmlFile(processFile);
		return "strResult";
	}
	
	/**
	 * 流程删除
	 * @return strResult
	 */
	public String unDeployProcessDefinition(){
		bpd.unDeployProcessDefinition(deploymentId);
    	return "strResult";
	};
	
	/**
	 * 根据流程定义ID获取流程图
	 * @return imageInputStream
	 */
	public String getProcessImage(){
		imageInputStream = bpi.getProcessImage(processDefinitionId);
		return "imageInputStream";
	}
	
	public String getProcessXml(){
		rawXml = bpi.getProcessXml(processDefinitionId);
		return "rawXml";
	}
	
	public String getXmlByPid(){
		String deployUrl =FlowDesigner.PROCESS_FILE_PATH+"/"+processDefinitionId+".jpdl.xml";
		File file = new File(deployUrl);
        try {
        	InputStream in = new FileInputStream(file);
        	BufferedReader reader = new BufferedReader(new InputStreamReader(in,"UTF-8")); // 实例化输入流，并获取网页代码
	        String s; // 依次循环，至到读的值为空
	        StringBuilder sb = new StringBuilder();
			while ((s = reader.readLine()) != null) {
				sb.append(s);
			}
			reader.close();
			rawXml = sb.toString();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return "rawXml";
	}
	/**
	 * 根据流程布署ID获取流程图
	 * @return imageInputStream
	 */
	public String getProcessImageByDeploymentId(){
		imageInputStream = bpi.getProcessImageByDeploymentId(deploymentId);
		return "imageInputStream";
	}
	
	/**
	 * 根据流程实例ID获取
	 * @return traceInstance
	 */
	public String getActivityCoordinates(){
		activityHistoryCoordinatesDTO = bpi.getHistoryActivityCoordinates(pid);
		activityCoordinatesDTO = bpi.getActivityCoordinates(pid);
		processDefinitionId = bpi.getProcessDefinitionIdByPid(pid);
		return "traceInstance";
	}
	
	/**
	 * 根据流程定义ID获取其流程实例
	 * @return SUCCESS
	 */
	public String findPageProcessInstance(){
      int start = (page - 1) * rows;
      pageDTO = bpi.findPageProcessInstance(processHistoriesQueryDTO.getProcessDefinitionId(), start, rows);
      pageDTO.setPage(page);
      pageDTO.setRows(rows);
      return SUCCESS; 
	}
	
	/**
	 * 分页查找历史流程实例
	 * @return SUCCESS
	 */
	public String findPageHistoryProcessInstance(){
		int start = (page - 1) * rows;
		pageDTO = bpi.findPageHistoryProcessInstance(processHistoriesQueryDTO, start, rows);
		pageDTO.setPage(page);
		pageDTO.setRows(rows);
		return SUCCESS; 
	}
	
	/**
	 * 查询历史任务
	 * @return SUCCESS
	 */
	public String findHistoryTask(){
		int start = (page - 1) * rows;
		pageDTO = bpi.findHistoryTask(pid,assignee,start, rows);
		pageDTO.setPage(page);
		pageDTO.setRows(rows);
		return SUCCESS; 
	}
	
	/**
	 * 任务指派
	 * @return SUCCESS
	 */
	public String assignTask(){
		bpi.assignTask(taskId, assignee);
		return SUCCESS;
	}
	
	/**
	 * 取得下一个流程活动
	 * @return strResult
	 */
	public String getNextActivity(){
		strResult = bpi.getNextActivity(pid, activityName, outcome);
		return "strResult";
	}
	
	/**
	 * 查询流程活动详细
	 * @return flowActivityDTO
	 */
	public String findFlowActivity(){
		String nextActivityName = bpi.getNextActivity(pid, activityName, outcome);
		String processDefinitionId = bpi.getProcessDefinitionIdByPid(pid);
		flowActivityDTO = flowPropertyService.findFlowActivity(processDefinitionId, new String[]{"task","foreach","join"}, nextActivityName);
		bpi.findLastCompleteHistoryActivityInstance(pid);
		return "flowActivityDTO";
	}
	
	/**
	 * 分页查询个人流程任务
	 * @return SUCCESS
	 */
	public String findPagePersonalTasks(){
		int start = (page - 1) * rows;
		pageDTO = bpi.findPagePersonalTasks(assignee, start, rows);
		pageDTO.setPage(page);
		pageDTO.setRows(rows);
		return SUCCESS; 
	}
	
	/**
	 * 分页查询指派我组的任务
	 * @return pageDTO
	 */
	public String findPageGroupTasks(){
		pageDTO = bpi.findPageGroupTasks(assignee, page, rows);
		pageDTO.setPage(page);
		pageDTO.setRows(rows);
		return SUCCESS; 
	}
	
	/**
     * 布署流程
     * @return success
     * @throws Exception
     */
	@Deprecated
    public String deployProcess() throws Exception {

        return SUCCESS;
    }

    /**
     * delete jbpm process（删除流程定义）
     * @return String
     * @throws Exception
     */
    public String undeployProcess() throws Exception {
    	bpd.unDeployProcessDefinition(deploymentId);
        return SUCCESS;
    }

    /**
     * 通过XSLT转JPDL
     * @return String
     */
    public String rawToJPDL(){
    	FlowDesigner fd  = new FlowDesigner();
    	rawXml=rawXml.replace("$", "&");
    	fd.RawToJPDL(rawXml);
    	return SUCCESS;
    }
    
    /**
     * 查找Node
     * @return String
     */
    public String findNodeByNodeName(){
    	FlowDesigner fd  = new FlowDesigner();
    	File xmlfile = new File(FlowDesigner.PROCESS_FILE_PATH+"/result.jpdl.xml");
    	nodeDTOList=fd.findNodeByNodeName(xmlfile,nodeDTO.getNodeTag());
    	return "nodeDTOList";
    }
    
    /**
     * 更新Node
     * @return String
     */
    public String updateNode(){
    	FlowDesigner fd  = new FlowDesigner();
    	File xmlfile = new File(FlowDesigner.PROCESS_FILE_PATH+"/result.jpdl.xml");
    	fd.updateNode(xmlfile, nodeDTO);
    	return SUCCESS;
    }
    
    /**
     * 导出JPDL
     * @return String
     */
    public String exportJpdlFile(){
    	jpdlFileFileName=new Date().getTime()+".jpdl.xml";
    	File jbpmfile = new File(FlowDesigner.PROCESS_FILE_PATH+"/result.jpdl.xml");
    	try {
    		if (!jbpmfile.exists()) {
    			throw new ApplicationException("ERROR_ATTACHMENT_NOT_EXISTS\n");
    		}else{
    			exportStream = new FileInputStream(jbpmfile);
    		}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			LOGGER.error("export JpdlFile", e);
		}
		
    	return "export";
    }

    /**
     * 当前活动
     * @return String
     */
    public String findActivityNamesByInstance(){
    	strSet=jbpmFacade.getActivityNamesByInstance(jbpmFacade.getInstanceById(instanceId));
    	return "strSet";
    }
    
    /**
     * 获取流程出口
     * @return String
     */
    public String getOutcomes(){
    	strSet=jbpmFacade.getOutcomes(instanceId);
    	return "strSet";
    }
    
    /**
     * 查询代理任务
     * @return String
     */
    public String findPageProxyTasks(){
		queryDTO.setAssignee(assignee);
		int start = (page - 1) * rows;
		pageDTO = bpi.findJbpmTaskPager(queryDTO,sidx,sord,start,rows);
		pageDTO.setPage(page);
		pageDTO.setRows(rows);
		return SUCCESS; 
	}
    
    /**
     * 获取流程实例详细
     * @return String
     */
    public String processDetail(){
    	processDetailDTO=bpi.findProcessInstanceDetail(pid);
    	return "processDetail";
    }
    
    /**
     * 是否已存在任务ID
     * @return String
     */
    public String ifExistTaskId(){
    	result = flowPropertyService.isExistTaskId(taskId);
    	return "result";
    }
    
    /**
     * 布署自定生成的流程文件
     * @return process definition id
     */
    public String deployJpdlFileByDrawingPage(){
    	String deployUrl =FlowDesigner.PROCESS_FILE_PATH+"/result.jpdl.xml";
    	File jpdlRawFile = new File(deployUrl);
		try {
			FileUtils.writeStringToFile(jpdlRawFile, rawXml,"UTF-8");
		} catch (IOException e1) {
			LOGGER.error("write xml",e1);
		}
    	strResult = bpd.deployProcessDefinitionXmlFile(new File(deployUrl));

    	strResult = flowPropertyService.findFlowPropertyByDeploymentId(strResult);
    	
		return "strResult";
    }
}